Ext.ns('Ext.ux.state');

(function(){
	/**
     * @class UserDataStorage
	 * This DataStorage implementation will be used in the case of IE6-7,
	 * that is, in the case where window.localStorage is not detected
	 * @param {Object} provider
     * @author Radu Brehar
	 */
	var UserDataStorage = function(provider){

		this.provider = provider;

		this.prefix = this.initialPrefix = 'userdatastorage-';
		this.prefix += this.provider.userid+'_';

		var textAreaId = Ext.id();

		Ext.getBody().insertHtml('beforeEnd',
		'<form>'+
			"<textarea id='"+textAreaId+"' style=\"display:none; behavior:url('#default#userData')\"></textarea>"+
		'</form>'
		);

		var storageArea = Ext.get(textAreaId),
			storageDom = storageArea.dom;

		if (!storageDom.addBehavior){
			throw 'Cannot use UserDataStorage. Browser incompatible.'
		};

		/**
		 * I have found no way to get all attributes on the element.
		 * Because of this, at each set, we update an array of existing attributes,
		 * which is set as the value for the this.initialPrefix attribute
		 * @param {Object} name
		 * @param {Object} value
		 */
		this.set = function(name, value){
			var arr = Ext.decode(storageDom.getAttribute(this.initialPrefix)) || [],
				attributeName = this.prefix+name;

			if (arr.indexOf(attributeName) == -1){
				arr.push(attributeName);
			}
			storageDom.setAttribute(this.initialPrefix, Ext.encode(arr));
			storageDom.setAttribute(attributeName, Ext.encode(value));
			storageDom.save(this.prefix);
		};

        this.clearAll = function(){
            var arr = Ext.decode(storageDom.getAttribute(this.initialPrefix)) || [];

            for (var i=0, len = arr.length; i<len; i++){
                storageDom.removeAttribute(arr[i]);
            }

            storageDom.setAttribute(this.initialPrefix, Ext.encode([]));
        };

		this.readStorage = function(){
			storageDom.load(this.prefix);

			var attributes = Ext.decode(storageDom.getAttribute(this.initialPrefix)) || [],
				len = attributes.length,
				valueObject = {}, key;

			for (var i=0; i<len; i++){
				key = attributes[i];
				if(key && key.indexOf(this.prefix) == 0){
					//console.log('found key: ', key);
	                valueObject[key.substr(this.prefix.length)] = Ext.decode(storageDom.getAttribute(key));
					storageDom.value = storageDom.getAttribute(key);
	            }
			}
			//console.log(Ext.encode(valueObject));

			return valueObject;
		}

	};

	var HTML5LocalStorage = function(provider){
		this.provider = provider;

		this.prefix = 'localstorage-';
		this.prefix += this.provider.userid+'_';

		this.set = function(name, value){
			//console.log('set ',name,' to ', value);
			window.localStorage.setItem(this.prefix+name, Ext.encode(value));
		};

		this.clear = function(name){
			window.localStorage.removeItem(this.prefix+name);
		};

        this.clearAll = function(){
            window.localStorage.clear();
        };

		this.readStorage = function(){
			var storage = localStorage,
				len = storage.length,
				key,
				valueObject = {};

			//console.log('local storage length is ', len, ' and prefix is ', this.prefix);

			for (var i=0; i<len; i++){
				key = storage.key(i);
				if(key && key.indexOf(this.prefix) == 0){
					//console.log('found key: ', key);
	                valueObject[key.substr(this.prefix.length)] = Ext.decode(storage.getItem(key));
	            }
			}
			//console.log('return ', valueObject);

			return valueObject;
		};
	};

    /**
     * @class Ext.ux.state.LocalProvider
     * @extends Ext.state.Provider
     * Usage:
     *   Ext.state.Manager.setProvider(new Ext.ux.state.LocalProvider({
     *       userid: <a user id>
     *   }));
     */
	var LocalProvider = Ext.extend(Ext.state.Provider,{
		/**
		 * a user id - will be useful in situations when multiple users
		 * use the same computer&browser, so the state will not be shared by them
		 * @param {Object} config
		 */
		userid: '',

	    constructor : function(config){
	        LocalProvider.superclass.constructor.call(this);

	        Ext.apply(this, config);
			/**
			 * we actually decide what storage to use by detecting existing posibilities:
			 * localStorage or userDate(in case of ie6+7)
			 * and delegate all responsabilities to the implementation
			 */
			this.actualProvider = this.getActualProvider();
	        this.state = this.actualProvider.readStorage();
            console.debug('state', this.state);
	    },

		getActualProvider: function(){
			if (window.localStorage) {
				//console.log('localStorage');
				return new HTML5LocalStorage(this);
			} else if (Ext.isIE){
				//console.log('userdataStorage');
				return new UserDataStorage(this);
			} else {
				throw 'LocalProvider not supported'
			}
		},

	    // private
	    set : function(name, value){
	        if(typeof value == "undefined" || value === null){
	            this.clear(name);
	            return;
	        }
	        this.actualProvider.set(name, value);
	        LocalProvider.superclass.set.call(this, name, value);
	    },

	    // private
	    clear : function(name){
	        this.actualProvider.clear(name);
	        LocalProvider.superclass.clear.call(this, name);
	    },

        clearAll: function(){
            this.actualProvider.clearAll();
        },

        getKeysStartingWith: function(str){
            var state = this.actualProvider.readStorage(),
                keys = [];

            for (var i in state){
                if (i.indexOf(str) == 0){
                    keys.push(i);
                }
            }

            return keys;
        }
	});

	Ext.ux.state.LocalProvider = LocalProvider;
})();
